package com.my.ycv51.ycinit.impl;

import android.content.Context;

import com.cloudwalk.android.CWCameraDataCallback;
import com.cloudwalk.android.CWCaptureImage;
import com.cloudwalk.android.CWDefine;
import com.cloudwalk.android.CWDetectCallback;
import com.cloudwalk.android.CWFaceRect;
import com.cloudwalk.android.CWFeature;
import com.cloudwalk.android.CWLDImage;
import com.cloudwalk.android.CWLiveEngineSDK;
import com.cloudwalk.android.CWPathInfo;
import com.cloudwalk.android.CWRet;

import java.util.Objects;

/**
 * @author YCKJ0827
 */
public class CWLiveEngine {

    private final static CWLiveEngine mInstance = new CWLiveEngine();

    private long mSDKEngineHandle = 0;

    private OnEngineInterfaceCallListener onEngineInterfaceCallListener;

    public interface OnEngineInterfaceCallListener {

        /**
         * Refresh ui int the method
         */
        void onEngineInterfaceCall(String msg);
    }

    private synchronized void addInvokeLogInfo(String logMsg) {
        if (onEngineInterfaceCallListener != null) {
            onEngineInterfaceCallListener.onEngineInterfaceCall(logMsg);
        }
    }

    public void addEngineInterfaceCallListener(OnEngineInterfaceCallListener onEngineInterfaceCallListener) {
        this.onEngineInterfaceCallListener = onEngineInterfaceCallListener;
    }

    public long getSDKEngine() {
        return mSDKEngineHandle;
    }

    public static CWLiveEngine getInstance() {
        return mInstance;
    }

    public boolean isInitialized() {
        return mSDKEngineHandle != 0;
    }

    public CWRet<Long> init(Context context, CWPathInfo pathInfo, CWDefine.CWLDEnumLiveMode liveMode, CWDefine.CWEnumCameraOpenMode cameraOpenMode) {
        synchronized (this) {
            addInvokeLogInfo("Init->start:\nconfigureParam: "
                    + Objects.toString(pathInfo) + "\nliveMode: " + liveMode + "  cameraOpenMode: " + cameraOpenMode);
            CWRet<Long> cwRet = CWLiveEngineSDK.instance.cwLDEngine_Init(context, pathInfo, liveMode, cameraOpenMode);
            if (cwRet.errorCode == CWDefine.CW_SDK_SUCCESS && cwRet.obj != 0) {
                mSDKEngineHandle = (long)cwRet.obj;
            }
            addInvokeLogInfo("Init->end");
            return cwRet;
        }
    }

    public CWRet unInit() {
        synchronized (this) {
            addInvokeLogInfo("UnInit->start:mSDKEngineHandle: " + mSDKEngineHandle);
            CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_UnInit(mSDKEngineHandle);
            mSDKEngineHandle = 0;
            addInvokeLogInfo("UnInit->end");
            return cwRet;
        }
    }

    public CWRet<String> getParam() {
        synchronized (this) {
            addInvokeLogInfo("GetParam->start:mSDKEngineHandle: " + mSDKEngineHandle);
            CWRet<String> cwRet = CWLiveEngineSDK.instance.cwLDEngine_GetParam(mSDKEngineHandle);
            addInvokeLogInfo("GetParam->end");
            return cwRet;
        }
    }

    public CWRet setParam(String jsonParam) {
        synchronized (this) {
            addInvokeLogInfo("SetParam->start:mSDKEngineHandle: " + mSDKEngineHandle + "  jsonParam: " + jsonParam);
            CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_SetParam(mSDKEngineHandle, jsonParam);
            addInvokeLogInfo("SetParam->end");
            return cwRet;
        }
    }

    public CWRet setEventCallback(CWDetectCallback func, Object userParam) {
        synchronized (this) {
            addInvokeLogInfo("SetEventCallback->start:mSDKEngineHandle: " + mSDKEngineHandle);
            CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_SetEventCallback(mSDKEngineHandle, func, userParam);
            addInvokeLogInfo("SetEventCallback->end");
            return cwRet;
        }
    }

    public CWRet startDetect(CWDefine.CWEnumDetectType type, int timeoutMilliSeconds) {
        synchronized (this) {
            addInvokeLogInfo("StartDetect->start:mSDKEngineHandle: "
                    + mSDKEngineHandle
                    + "  type: " + type + "  timeout: " + timeoutMilliSeconds);
            CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_StartDetect(mSDKEngineHandle, type, timeoutMilliSeconds);
            addInvokeLogInfo("StartDetect->end");
            return cwRet;
        }
    }

    public CWRet stopDetect() {
        synchronized (this) {
            addInvokeLogInfo("StopDetect->start:mSDKEngineHandle: " + mSDKEngineHandle);
            CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_StopDetect(mSDKEngineHandle);
            addInvokeLogInfo("StopDetect->end");
            return cwRet;
        }
    }

    public CWRet openCamera(CWDefine.CWLDEnumCamType type) {
        synchronized (this) {
            addInvokeLogInfo("OpenCamera->start:mSDKEngineHandle: " + mSDKEngineHandle + "  cameraType: " + type);
            CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_OpenCamera(mSDKEngineHandle, type);
            addInvokeLogInfo("OpenCamera->end");
            return cwRet;
        }
    }

    public CWRet setCameraDataCallback(CWDefine.CWLDEnumCamType type,
                                                  CWCameraDataCallback func,
                                                  CWDefine.CWEnumCameraDataFormat format,
                                                  boolean draw_face_rect,
                                                  Object user_param) {
        synchronized (this) {
            addInvokeLogInfo("SetCameraDataCallback->start:mSDKEngineHandle: " + mSDKEngineHandle + "  cameraType: " + type);
            CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_SetCameraDataCallback(mSDKEngineHandle, type, func, format, draw_face_rect, user_param);
            addInvokeLogInfo("SetCameraDataCallback->end");
            return cwRet;
        }
    }

    public CWRet closeCamera(CWDefine.CWLDEnumCamType type) {
        synchronized (this) {
            addInvokeLogInfo("CloseCamera->start:mSDKEngineHandle: " + mSDKEngineHandle + "  cameraType: " + type);
            CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_CloseCamera(mSDKEngineHandle, type);
            addInvokeLogInfo("CloseCamera->end");
            return cwRet;
        }
    }

    public CWRet setCameraRotateAndMirror(CWDefine.CWLDEnumCamType type,
                                                     CWDefine.CWEnumCameraDataAngle angle,
                                                     CWDefine.CWEnumCameraDataMirror mirror) {
        synchronized (this) {
            addInvokeLogInfo("SetCameraRotateAndMirror->start:"
                    + " SDKHandle: " + mSDKEngineHandle
                    + "  cameraType: " + type
                    + "  angle: " + angle
                    + "  mirror: " + mirror);
            CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_SetCameraRotateAndMirror(mSDKEngineHandle, type, angle, mirror);
            addInvokeLogInfo("SetCameraRotateAndMirror->end");
            return cwRet;
        }
    }

    public CWRet setCameraStreamFormat(CWDefine.CWLDEnumCamType type, CWDefine.CWEnumCameraStreamFormat format, int width, int height, int fps) {
        synchronized (this) {
            addInvokeLogInfo("SetCameraStreamFormat->start:"
                    + " SDKHandle: " + mSDKEngineHandle
                    + "  cameraType: " + type + "  format: " + format
                    + "  width: " + width + "  height: " + height + "  fps: " + fps);
            CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_SetCameraStreamFormat(mSDKEngineHandle, type, format, width, height, fps);
            addInvokeLogInfo("SetCameraStreamFormat->end");
            return cwRet;
        }
    }

    public CWRet cameraStreamOn(CWDefine.CWLDEnumCamType type, boolean streamOn) {
        synchronized (this) {
            addInvokeLogInfo("CameraStreamOn->start:"
                    + " SDKHandle: " + mSDKEngineHandle
                    + "  cameraType: " + type + "  streamOn: " + streamOn);
            CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_CameraStreamOn(mSDKEngineHandle, type, streamOn);
            addInvokeLogInfo("CameraStreamOn->end");
            return cwRet;
        }
    }

    public CWRet<CWDefine.CWEnumCameraStatus> getCameraStatus(CWDefine.CWLDEnumCamType type) {
        synchronized (this) {
            addInvokeLogInfo("GetCameraStatus->start:"
                    + " SDKHandle: " + mSDKEngineHandle + "  cameraType: " + type);
            CWRet<CWDefine.CWEnumCameraStatus> cwRet = CWLiveEngineSDK.instance.cwLDEngine_GetCameraStatus(mSDKEngineHandle, type);
            addInvokeLogInfo("GetCameraStatus->end");
            return cwRet;
        }
    }

    public CWRet<CWCaptureImage> captureImage(CWDefine.CWLDEnumCamType type, CWDefine.CWEnumImageFormat format, boolean isBase64) {
        synchronized (this) {
            addInvokeLogInfo("CaptureImage->start:"
                    + " SDKHandle: " + mSDKEngineHandle
                    + "  cameraType: " + type + "  captureFormat: " + format + "  isBase64: " + isBase64);
            CWRet<CWCaptureImage> cwRet = CWLiveEngineSDK.instance.cwLDEngine_CaptureImage(mSDKEngineHandle, type, format, isBase64);
            addInvokeLogInfo("CaptureImage->end");
            return cwRet;
        }
    }

    public CWRet<CWCaptureImage> getDetectedImage(CWDefine.CWLDEnumCamType type, CWDefine.CWEnumImageFormat format, boolean isBase64, CWDefine.CWLDEnumLiveImageType imageType) {
        synchronized (this) {
            addInvokeLogInfo("GetDetectedImage->start:"
                    + " SDKHandle: " + mSDKEngineHandle
                    + "  cameraType: " + type.ordinal() + "  captureFormat: " + format.ordinal()
                    + "  isBase64: " + isBase64 + "  liveImageType: " + imageType.ordinal());
            CWRet<CWCaptureImage> cwRet = CWLiveEngineSDK.instance.cwLDEngine_GetDetectedImage(mSDKEngineHandle, type, format, isBase64, imageType);
            addInvokeLogInfo("GetDetectedImage->end");
            return cwRet;
        }
    }

    public CWRet setDisplayWindow(CWDefine.CWLDEnumCamType type, Object displayWindow) {
        addInvokeLogInfo("SetDisplayWindow->start:"
                + " SDKHandle: " + mSDKEngineHandle
                + "  cameraType: " + type + "  displayWindow: " + displayWindow);
        CWRet cwRet = CWLiveEngineSDK.instance.cwLDEngine_SetDisplayWindow(mSDKEngineHandle, type, displayWindow);
        addInvokeLogInfo("SetDisplayWindow->end");
        return cwRet;
    }

    public CWRet<Integer> getFeatureLength() {
        synchronized (this) {
            addInvokeLogInfo("GetFeatureLength->start:" + " SDKHandle: " + mSDKEngineHandle);
            CWRet<Integer> cwRet = CWLiveEngineSDK.instance.cwLDEngine_GetFeatureLength(mSDKEngineHandle);
            addInvokeLogInfo("GetFeatureLength->end");
            return cwRet;
        }
    }

    public CWRet<CWFeature> getFeature(CWLDImage image, CWFaceRect rect, boolean onlyKeypt) {
        synchronized (this) {
            addInvokeLogInfo("GetFeature->start:"
                    + " SDKHandle: " + mSDKEngineHandle
                    + "  image: " + image + "  rect: " + Objects.toString(rect));
            CWRet<CWFeature> cwRet = CWLiveEngineSDK.instance.cwLDEngine_GetFeature(mSDKEngineHandle, image, rect, onlyKeypt);
            addInvokeLogInfo("GetFeature->end");
            return cwRet;
        }
    }

    public CWRet<float[]> compareFeature(byte[] proboFeature, byte[] filedFeature, int filedNum) {
        synchronized (this) {
            addInvokeLogInfo("CompareFeature->start:" + " SDKHandle: " + mSDKEngineHandle);
            CWRet<float[]> cwRet = CWLiveEngineSDK.instance.cwLDEngine_CompareFeature(mSDKEngineHandle, proboFeature, filedFeature, filedNum);
            addInvokeLogInfo("CompareFeature->end");
            return cwRet;
        }
    }
}
